﻿using UnityEngine;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UBlockly.Graphic;
using System.Reflection;
using System.Text;
using System;
using UnityEngine.UI;

namespace UBlockly.Scriptable
{
    internal sealed class ILTranslate
    {
        sealed class BlockEntryFunction
        {
            Dictionary<string,Delegate> translateFunctionDic = new Dictionary<string, Delegate>(100);

             public void RegistApi(IBlockApi apiObj)
             {
                 Type type = apiObj.GetType();
                 var methods = type.GetMethods();
                 foreach (var method in methods)
                 {
                     if (method.GetCustomAttribute(typeof(BlockDescribeAttribute)) == null)
                         continue;
                     RegistApi(method, apiObj);
                 }
             }
             public void RegistApi(MethodInfo method,object runtimeObj)
             {
                 if (!TranslateHelper.IsBlockMethod(method))
                     throw new Exception($"函数{method.Name}不符合block函数定义");
                 Type delType = null;
                 var functionDefineStr = TranslateHelper.ParseMethodToFuncDefineStr(method);
                 var ilfuncTypeStr = TranslateHelper.ParseFuncTypeStr(functionDefineStr);
                 if(FuncTypeDic.TryGetValue(ilfuncTypeStr, out delType))
                 {
                     Debug.LogError("out delType = "+delType);
                     var del = Delegate.CreateDelegate(delType, runtimeObj, method);
                     RegistFunction(method.Name, del);
                 }
                 else
                 {
                     Debug.LogError("LoadApi error,no key:" + ilfuncTypeStr);
                 }
             }

             public bool TryGetFunction(string functionName, out Delegate function)
             {
                 return translateFunctionDic.TryGetValue(functionName, out function);
             }
             public void RegistFunction(string funname, System.Delegate del)
             {
                 Debug.Log($"注册函数{funname}");
                 if (!translateFunctionDic.ContainsKey(funname))
                 {
                     translateFunctionDic.Add(funname, del);
                 }
                 else
                 {
                     throw new Exception($"RegistFunction Error, Repeat Regist:{funname}");
                 }
             }
        }
        sealed class InnerApi
        {
            public BoolR GetBoolR(bool value)
            {
                return new BoolR(){Value = value};
            }
            public IntR GetIntR(int value)
            {
                return new IntR() {Value = value};
            }

            public FloatR GetFloatR(float value)
            {
                return new FloatR() {Value = value};
            }
            
            public StringR GetStringR(string value)
            {
                return new StringR() {Value = value};
            }
        }

        private UBlockEntry blockEntry;
        private static InnerApi innerApi;
        static Dictionary<string, Type> FuncTypeDic = new Dictionary<string, Type>(100);
        private static Dictionary<int, BlockEntryFunction> blockEntryMap;
        #region 函数库导入

        public static void Init()
        {
            blockEntryMap = new Dictionary<int, BlockEntryFunction>();
            blockEntryMap.Add(0,new BlockEntryFunction());
            GeneratorILFuncMap();
            InitInnerApi();
        }

        public static void UnRegistBlockEntryApi(int entryHash)
        {
            BlockEntryFunction entryFunction;
            if (blockEntryMap.TryGetValue(entryHash, out entryFunction))
            {
                entryFunction = null;
                blockEntryMap.Remove(entryHash);
            }
        }

        public static void RegistApi(int hash, IBlockApi api)
        {
            if (!blockEntryMap.ContainsKey(hash))
            {
                blockEntryMap.Add(hash,new BlockEntryFunction());
            }
            blockEntryMap[hash].RegistApi(api);
        }

        public static void RegistApi(int hash, MethodInfo method,object runtimeObj)
        {
            if (!blockEntryMap.ContainsKey(hash))
            {
                blockEntryMap.Add(hash,new BlockEntryFunction());
            }

            blockEntryMap[hash].RegistApi(method, runtimeObj);
        }

        public static void RegistApi(int hash, string methodName, Delegate del)
        {
            if (!blockEntryMap.ContainsKey(hash))
            {
                blockEntryMap.Add(hash,new BlockEntryFunction());
            }

            blockEntryMap[hash].RegistFunction(methodName, del);
        }
        #endregion
        #region 函数类型获取Node类型,特殊函数Node
        public static Type GetNodeType(NodeScriptType scriptType)
        {
            Type nodeType = null;
            //所有特殊函数都需要特殊node实现
            switch (scriptType)
            {
                case NodeScriptType.ComplexType:
                    nodeType = typeof(UI.ComplexNode);
                    break;
                default:
                    nodeType = typeof(UI.NormalNode);
                    break;
            }
            return nodeType;
        }
        #endregion
        
        #region 自带函数初始化
        static void InitInnerApi()
        {
            var entryFunction = blockEntryMap[0];
            innerApi = new InnerApi();
            var strDel = Delegate.CreateDelegate(typeof(Func<string,StringR>), innerApi,innerApi.GetType().GetMethod("GetStringR"));
            entryFunction.RegistFunction("GetStringR", strDel);
            var intDel = Delegate.CreateDelegate(typeof(Func<int,IntR>), innerApi, innerApi.GetType().GetMethod("GetIntR"));
            entryFunction.RegistFunction("GetIntR", intDel);
            var boolDel = Delegate.CreateDelegate(typeof(Func<bool,BoolR>), innerApi, innerApi.GetType().GetMethod("GetBoolR"));
            entryFunction.RegistFunction("GetBoolR", boolDel);
        }
        static void GeneratorILFuncMap()
        {
             //FuncTypeDic.Add(ILFuncType.IntR,DD.func1.GetType());
            // var ass = AppDomain.CurrentDomain.Load("UBlockly.Runtime");
             var funcTypeEnum = System.Reflection.Assembly.GetExecutingAssembly().GetType("UBlockly.Runtime.ILFuncType");
             Debug.LogError("a:"+ Assembly.GetExecutingAssembly().FullName);
             //var funcTypeEnum = ass.GetType("UBlockly.Runtime.ILFuncType");
             var enumFields = funcTypeEnum.GetFields(BindingFlags.Public | BindingFlags.Static);
             var delegateType = Assembly.GetExecutingAssembly().GetType("UBlockly.Runtime.ILFunctionDelegate");
             var delegateFields = delegateType.GetFields(BindingFlags.Public | BindingFlags.Static);
             
             if(enumFields.Length != delegateFields.Length)
                 throw new Exception("GeneratorILFuncMap error,check generate files");
             for (int i = 0; i < enumFields.Length; i++)
             {
                 var type = delegateFields[i];
                 FuncTypeDic.Add(enumFields[i].Name, type.FieldType);
             }
             Debug.Log("GeneratorILFuncMap success!");
        }
        

        #endregion

        public static IVarObject ExF(string functionName, params object[] args)
        {
            var fk = ParseFunctionEntry(functionName);
            var blockFunction = blockEntryMap[fk.Key];
            Delegate function;
            if (blockFunction.TryGetFunction(fk.Value, out function))
            {
                Debug.Log($"函数执行,delegateType:{function.GetMethodInfo().ToString()},参数个数：{args?.Length}");
                return (IVarObject)function.DynamicInvoke(args);
            }
            throw new System.Exception($"ExF 时出现未知错误，functionName:{functionName}-{fk.Key}-{fk.Value}");
        }

        static KeyValuePair<int,string> ParseFunctionEntry(string functionName)
        {
            var index = functionName.Substring(0, functionName.IndexOf('$'));
            string fn = functionName.Replace($"{index}$","");
            var n = int.Parse(index);
            return new KeyValuePair<int, string>(n,fn);
        }
    }
    
}


